package com.gitee.feizns.convert.method.valueof;

import com.gitee.feizns.convert.method.AbstractMethodConverter;
import com.gitee.feizns.convert.method.MethodSelectionStrategyList;
import com.gitee.feizns.convert.method.MethodWrapper;
import com.gitee.feizns.reflect.MethodUtils;

import java.lang.reflect.Method;
import java.util.stream.Stream;

/**
 * 单参数 valueOf(params) 转换策略
 * @author feizns
 * @since 2019/5/27
 */
public class SingleParameterValueOfConverter extends AbstractValueOfMethodConverter {

    @Override
    protected Stream<Method> filterMethod(Stream<Method> methodStream) {
        return methodStream.filter(method -> method.getParameterCount() == 1);
    }

    @Override
    protected MethodSelectionStrategyList getSelectionStrategy(Class<?> targetType) {
        return new MethodSelectionStrategyList(
            new MethodSelectionStrategyByParameterImpl(),
            new MethodSelectionStrategyByConverterImpl(this)
        );
    }

    //根据方法的参数最优匹配选择最优的方法
    private class MethodSelectionStrategyByParameterImpl extends AbstractMethodSelectionStrategyByParameter {

        @Override
        protected boolean isYou(Method method, Class<?> clz) {
            return method.getParameterTypes()[0] == clz;
        }

        @Override
        protected MethodWrapper getInvokeStrategy(Method method, Class<?> targetType, Object original) {
            return () -> method == null ? null : MethodUtils.invoke(method, original);
        }

    }

    //根据支持的转换器列表寻找最优的方法
    private class MethodSelectionStrategyByConverterImpl extends AbstractMethodSelectionStrategyByConverter {

        public MethodSelectionStrategyByConverterImpl(AbstractMethodConverter abstractMethodConverter) {
            super(abstractMethodConverter);
        }

        @Override
        protected Class<?> getType(Method method) {
            return method.getParameterTypes()[0];
        }

        @Override
        protected Object invoke(Method method, Class<?> targetType, Object original) {
            return MethodUtils.invoke(method, original);
        }

    }

}
